package com.fengwk.support.util;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.fengwk.support.exception.BaseException;
import com.fengwk.support.function.Return;
import com.fengwk.support.util.LoggerUtils.Logger;

/**
 * 数组工具
 */
public final class ArrayUtils {

	private static final Logger LOG = LoggerUtils.getLogger(ArrayUtils.class);
	
	private ArrayUtils() {
		throw new BaseException("can not instance " + getClass());
	}
	
	/**
	 * 包含
	 * 
	 * @param array
	 * @param a
	 * @return
	 */
	public static <A> boolean contains(A[] array, A a){
		for(A buf: array) {
			if(ObjectUtils.equals(buf, a)) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 数组为空判断
	 * 
	 * @param array
	 * @return
	 */
	public static <A> boolean isBlank(A[] array) {
		return isBlankArray(array);
	}
	
	/**
	 * 数组非空判断
	 * 
	 * @param array
	 * @return
	 */
	public static <A> boolean isNotBlank(A[] array) {
		return isNotBlankArray(array);
	}
	
	/**
	 * 数组转字符串
	 * 
	 * @param strs
	 * @param separator
	 * @return
	 */
    public static String join(Object[] strs, String separator) {
    	if(isBlank(strs)) {
    		return null;
    	}
    	StringBuffer sb = new StringBuffer();
    	for(Object objStr: strs) {
    		sb.append(objStr == null ? "null" : objStr.toString());
    		sb.append(separator);
    	}
    	String res = sb.toString();
    	if(StringUtils.isNotBlank(res)) {
    		char[] chars = res.toCharArray();
    		res = new String(chars, 0, chars.length - 1);
    	}
    	return res;
    }

	/**
	 * 合并数组列表
	 * 
	 * @param list
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] mergeArryList(List<T[]> list) {
		return (T[]) mergeArryList(null, (List<?>) list);
	}
	
	/**
	 * 合并数组列表
	 * 
	 * @param list
	 * @return
	 */
	public static short[] mergeShortArryList(List<short[]> list) {
		return (short[]) mergeArryList(len -> new short[len], (List<?>) list);
	}
	
	/**
	 * 合并数组列表
	 * 
	 * @param list
	 * @return
	 */
	public static int[] mergeIntArryList(List<int[]> list) {
		return (int[]) mergeArryList(len -> new int[len], (List<?>) list);
	}
	
	/**
	 * 合并数组列表
	 * 
	 * @param list
	 * @return
	 */
	public static long[] mergeLongArryList(List<long[]> list) {
		return (long[]) mergeArryList(len -> new long[len], (List<?>) list);
	}
	
	/**
	 * 合并数组列表
	 * 
	 * @param list
	 * @return
	 */
	public static float[] mergeFloatArryList(List<float[]> list) {
		return (float[]) mergeArryList(len -> new float[len], (List<?>) list);
	}
	
	/**
	 * 合并数组列表
	 * 
	 * @param list
	 * @return
	 */
	public static double[] mergeDoubleArryList(List<double[]> list) {
		return (double[]) mergeArryList(len -> new double[len], (List<?>) list);
	}
	
	public static void main(String[] args) {
		double[] d1 = new double[] {1, 2, 3};
		double[] d2 = new double[] {4, 5};
		
		List<double[]> list = new ArrayList<>();
		list.add(d1);
		list.add(d2);
		double[] ds = mergeDoubleArryList(list);
		print(ds);
		
	}
	
	/**
	 * 合并数组列表
	 * 
	 * @param list
	 * @return
	 */
	public static byte[] mergeByteArryList(List<byte[]> list) {
		return (byte[]) mergeArryList(len -> new byte[len], (List<?>) list);
	}
	
	/**
	 * 合并数组列表
	 * 
	 * @param list
	 * @return
	 */
	public static char[] mergeCharArryList(List<char[]> list) {
		return (char[]) mergeArryList(len -> new char[len], (List<?>) list);
	}
	
	/**
	 * 合并数组列表
	 * 
	 * @param list
	 * @return
	 */
	public static boolean[] mergeBooleanArryList(List<boolean[]> list) {
		return (boolean[]) mergeArryList(len -> new boolean[len], (List<?>) list);
	}
	
	/**
	 * 数组合并
	 * 
	 * @param arrs
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] merge(T[]...arrs) {
		return (T[]) merge(null, (Object[]) arrs);
	}
	
	/**
	 * 数组合并
	 * 
	 * @param arrs
	 * @return
	 */
	public static short[] merge(short[]...arrs) {
		return (short[]) merge(len -> new short[len], (Object[]) arrs);
	}
	
	/**
	 * 数组合并
	 * 
	 * @param arrs
	 * @return
	 */
	public static int[] merge(int[]...arrs) {
		return (int[]) merge(len -> new int[len], (Object[]) arrs);
	}
	
	/**
	 * 数组合并
	 * 
	 * @param arrs
	 * @return
	 */
	public static long[] merge(long[]...arrs) {
		return (long[]) merge(len -> new long[len], (Object[]) arrs);
	}
	
	/**
	 * 数组合并
	 * 
	 * @param arrs
	 * @return
	 */
	public static float[] merge(float[]...arrs) {
		return (float[]) merge(len -> new float[len], (Object[]) arrs);
	}
	
	/**
	 * 数组合并
	 * 
	 * @param arrs
	 * @return
	 */
	public static double[] merge(double[]...arrs) {
		return (double[]) merge(len -> new double[len], (Object[]) arrs);
	}
	
	/**
	 * 数组合并
	 * 
	 * @param arrs
	 * @return
	 */
	public static byte[] merge(byte[]...arrs) {
		return (byte[]) merge(len -> new byte[len], (Object[]) arrs);
	}
	
	/**
	 * 数组合并
	 * 
	 * @param arrs
	 * @return
	 */
	public static char[] merge(char[]...arrs) {
		return (char[]) merge(len -> new char[len], (Object[]) arrs);
	}
	
	/**
	 * 数组合并
	 * 
	 * @param arrs
	 * @return
	 */
	public static boolean[] merge(boolean[]...arrs) {
		return (boolean[]) merge(len -> new boolean[len], (Object[]) arrs);
	}
	
	private static Object mergeArryList(Return.Params1<Object, Integer> newInstance, List<?> list) {
		Class<?> type = null;
		int len = 0;
		for (Object arr: list) {
			if (newInstance == null && type == null) 
				type = arr.getClass().getComponentType();
			len += getArrayLength(arr);
		}
		Object newArr = null;
		if (newInstance == null)
			newArr = newInstance(type, len);
		else
			newArr = newInstance.apply(len);
		int offset = 0;
		for (Object arr: list) {
			int l = getArrayLength(arr);
			System.arraycopy(arr, 0, newArr, offset, l);
			offset += l;
		}
		return newArr;
	}
	
	private static Object merge(Return.Params1<Object, Integer> newInstance, Object...arrs) {
		Class<?> type = null;
		int len = 0;
		for (Object arr: arrs) {
			if (newInstance == null && type == null) 
				type = arr.getClass().getComponentType();
			len += getArrayLength(arr);
		}
		Object newArr = null;
		if (newInstance == null)
			newArr = newInstance(type, len);
		else
			newArr = newInstance.apply(len);
		int offset = 0;
		for (Object arr: arrs) {
			int l = getArrayLength(arr);
			System.arraycopy(arr, 0, newArr, offset, l);
			offset += l;
		}
		return newArr;
	}
	
    /**
     * 移除数组下标位置元素,之后元素前进一位
     * 
     * @param array
     * @param index
     * @return
     */
	@SuppressWarnings("unchecked")
	public static <A> A[] remove(A[] array, int index) {
		return (A[]) removeArray(array, index);
    }
	
	/**
	 * 转换为list
	 * 
	 * @param array 数组对象
	 */
	public static <A> List<A> toList(A[] array) {
		if(array == null) {
			return null;
		}
		return Arrays.asList(array);
	}
	
	/**
	 * 转换为set
	 */
	public static <A> Set<A> toSet(A[] array) {
		if(array == null) {
			return null;
		}
		return (Set<A>) toCollection(array, new HashSet<A>());
	}
	
	/**
	 * 数组打印
	 * 
	 * @param array
	 */
	public static void print(Object array) {
		if(!isArray(array)) {
			return;
		}
		for(int i = 0; i < Array.getLength(array); i ++) {
			System.out.println(Array.get(array, i));
		}
	}
	
	/*
	 * 基本类型的扩展
	 */
	public static int[] remove(int[] array, int index) {
		return (int[]) removeArray(array, index);
    }
	
	public static float[] remove(float[] array, int index) {
		return (float[]) removeArray(array, index);
    }
	
	public static double[] remove(double[] array, int index) {
		return (double[]) removeArray(array, index);
    }
	
	public static long[] remove(long[] array, int index) {
		return (long[]) removeArray(array, index);
    }
	
	public static boolean[] remove(boolean[] array, int index) {
		return (boolean[]) removeArray(array, index);
    }
	
	public static byte[] remove(byte[] array, int index) {
		return (byte[]) removeArray(array, index);
    }
	
	public static char[] remove(char[] array, int index) {
		return (char[]) removeArray(array, index);
    }
	
	public static String[] remove(String[] array, int index) {
		return (String[]) removeArray(array, index);
    }
	
	public static boolean isBlank(int[] array) {
		return isBlankArray(array);
	}
	
	public static boolean isBlank(float[] array) {
		return isBlankArray(array);
	}
	
	public static boolean isBlank(double[] array) {
		return isBlankArray(array);
	}
	
	public static boolean isBlank(long[] array) {
		return isBlankArray(array);
	}
	
	public static boolean isBlank(boolean[] array) {
		return isBlankArray(array);
	}
	
	public static boolean isBlank(byte[] array) {
		return isBlankArray(array);
	}
	
	public static boolean isBlank(char[] array) {
		return isBlankArray(array);
	}

	public static boolean isBlank(String[] array) {
		return isBlankArray(array);
	}
	
	public static boolean isNotBlank(int[] array) {
		return isNotBlankArray(array);
	}
	
	public static boolean isNotBlank(float[] array) {
		return isNotBlankArray(array);
	}
	
	public static boolean isNotBlank(long[] array) {
		return isNotBlankArray(array);
	}
	
	public static boolean isNotBlank(double[] array) {
		return isNotBlankArray(array);
	}
	
	public static boolean isNotBlank(boolean[] array) {
		return isNotBlankArray(array);
	}
	
	public static boolean isNotBlank(byte[] array) {
		return isNotBlankArray(array);
	}
	
	public static boolean isNotBlank(char[] array) {
		return isNotBlankArray(array);
	}

	public static boolean isNotBlank(String[] array) {
		return isNotBlankArray(array);
	}
	
	// 数组为空判断
	private static boolean isBlankArray(Object array) {
		if(array == null) {
			return true;
		}
		if(!isArray(array)) {
			return false;
		}
		int len = getArrayLength(array);
		if(len <= 0) {
			return true;
		}
		return false;
	}
	
	// 数组非空判断
	private static boolean isNotBlankArray(Object array) {
		if(!isArray(array)) {
			return false;
		}
		if(isBlankArray(array)) {
			return false;
		}
		return true;
	}
	
	// 获取数组对象长度
	private static int getArrayLength(Object array) {
		return Array.getLength(array);
	}
	
	// 类型判断
	private static boolean isArray(Object obj) {
		if(obj == null) {
			return false;
		}
		if(TypeUtils.isArray(obj)) {
			return true;
		}
		LOG.error("Types of abnormal [Should be array]");
		return false;
	}
	
	// 转换为集合类型
	@SuppressWarnings("unchecked")
	private static <A> Collection<A> toCollection(A[] array, Collection<A> container) {
		if(!isArray(array)) {
			return null;
		}
		for(int i = 0; i < getArrayLength(array); i ++) {
			container.add((A) Array.get(array, i));
		}
		if(CollectionUtils.isBlank(container)) {
			return null;
		}
		return container;
	}
	
	// 移除数组index
	private static Object removeArray(Object array, int index) {
		if(isNotBlankArray(array)) {
			int len = getArrayLength(array);
			Object resArray = Array.newInstance(array.getClass().getComponentType(), len - 1);
	    	int offset = 0;
	    	for(int i = 0; i < len; i ++) {
	    		if(index == i) {
	    			offset ++;
	    		} else {
	    			Array.set(resArray, i - offset, Array.get(array, i));
	    		}
	    	}
	    	array = resArray;
		}
		return array;
    }
	
	/**
	 * 构建数组
	 * 
	 * @param componentType
	 * @param length
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <A> A[] newInstance(Class<A> componentType, int length) {
		return (A[]) Array.newInstance(componentType, length);
	}
	
	/**
	 * 构建多维数组
	 * 
	 * @param componentType
	 * @param dimensions
	 * @return
	 */
	public static Object newInstance(Class<?> componentType, int... dimensions) {
		return Array.newInstance(componentType, dimensions);
	}
	
}
